package com.molichuxing.services.infrastructure.service.impl;

import com.molichuxing.framework.dto.Paged;
import com.molichuxing.framework.dto.TabDto;
import com.molichuxing.services.infrastructure.bean.OfflineBean;
import com.molichuxing.services.infrastructure.convertor.Convert;
import com.molichuxing.services.infrastructure.dao.OfflineMapper;
import com.molichuxing.services.infrastructure.dto.request.create.OfflineCreateDto;
import com.molichuxing.services.infrastructure.dto.request.modify.OfflineAuditModifyDto;
import com.molichuxing.services.infrastructure.dto.response.OfflineAuditDto;
import com.molichuxing.services.infrastructure.dto.response.OfflineDto;
import com.molichuxing.services.infrastructure.service.OfflineService;
import com.molichuxing.services.property.OfflineAuditStatusEnum;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 线下支付 服务实现类
 * </p>
 *
 * @author zhaopenghui
 * @since 2019-08-21
 */
@Service("offlineService")
public class OfflineServiceImpl implements OfflineService {

    @Resource
    private OfflineMapper offlineMapper;

    /**
     * 添加线下支付
     *
     * @param offlineCreateDto
     * @return
     * @throws Exception
     */
    @Override
    public Integer createOffline(OfflineCreateDto offlineCreateDto) throws Exception {
        Assert.notNull(offlineCreateDto, "添加失败");
        createOfflineCheck(offlineCreateDto);

        OfflineBean offlineBean = Convert.toOfflineBean(offlineCreateDto);
        offlineBean.setAuditStatus(OfflineAuditStatusEnum.UNREVISED.getValue());
        offlineMapper.create(offlineBean);
        return offlineBean.getId();
    }


    /**
     * 校验
     *
     * @param offlineCreateDto
     * @throws Exception
     */
    private void createOfflineCheck(OfflineCreateDto offlineCreateDto) throws Exception {
        String serialNumber = offlineCreateDto.getSerialNumber();
        serialNumberCheck(serialNumber);
    }

    /**
     * 流水编号校验
     *
     * @param serialNumber
     * @throws Exception
     */
    private void serialNumberCheck(String serialNumber) throws Exception {
        List<Integer> list = new ArrayList<>();
        list.add(OfflineAuditStatusEnum.UNREVISED.getValue());
        list.add(OfflineAuditStatusEnum.APPROVE.getValue());

        OfflineBean offline = offlineMapper.getOffline(serialNumber, list);
        if (offline != null) {
            throw new IllegalArgumentException("流水编号已存在,请勿重复添加");
        }
    }

    /**
     * 线下支付审核信息
     *
     * @param offlineId
     * @return
     * @throws Exception
     */
    @Override
    public OfflineAuditDto getOfflineAudit(Integer offlineId) throws Exception {
        OfflineBean OfflineBean = offlineMapper.getById(offlineId);
        return Convert.toOfflineAuditDto(OfflineBean);
    }

    /**
     * 线下支付分页列表
     *
     * @param map      key:serialNumber String 流水编号
     *                 key:dealerId Integer 经销商id
     *                 key:auditStatus Integer 审核状态（0：未审核，1：审核通过，2：驳回）
     *                 key:payName String 付款方
     *                 key:repayType Integer 还款类型（1:经销商, 2:用户）
     *                 key:startApplyTime LocalDateTime 申请开始时间
     *                 key:endApplyTime LocalDateTime 申请结束时间
     * @param pageNum
     * @param pageSize
     * @return
     * @throws Exception
     */
    @Override
    public Paged<OfflineDto> getOfflinePage(Map<String, Object> map, Integer pageNum, Integer pageSize) throws Exception {
        long pageCount = offlineMapper.getPageCount(map);
        List<OfflineBean> offlineBeanList = null;
        if (pageCount > 0) {
            offlineBeanList = offlineMapper.getPage(map, pageNum, pageSize);
        }
        List<OfflineDto> offlineDtoList = Convert.toOfflineDtoList(offlineBeanList);
        return new Paged<OfflineDto>(offlineDtoList, pageCount, pageSize);
    }

    /**
     * 通过审核状态获取线下支付数量
     *
     * @return
     * @throws Exception
     */
    @Override
    public Map<Integer, Integer> getCountByAuditStatus(Integer dealerId) throws Exception {
        List<TabDto> statusList = offlineMapper.getCountByAuditStatus(dealerId);
        if (null == statusList || statusList.size() == 0) {
            return null;
        }

        Map<Integer, Integer> returnMap = new HashMap<>();
        for (TabDto tabDto : statusList) {
            Integer type = tabDto.getType();
            Integer count = tabDto.getCount();
            returnMap.put(type, count);
        }

        return returnMap;
    }

    /**
     * 获取审核状态数量
     *
     * @param dealerId
     * @return
     * @throws Exception
     */
    @Override
    public List<TabDto> getTabDto(Integer dealerId) throws Exception {
        Map<Integer, Integer> statusCountMap = getCountByAuditStatus(dealerId);

        List<TabDto> tabList = new ArrayList<>();
        for (OfflineAuditStatusEnum offlineAuditStatusEnum : OfflineAuditStatusEnum.values()) {
            int value = offlineAuditStatusEnum.getValue();
            String name = offlineAuditStatusEnum.getName();
            Integer count = 0;
            if (null != statusCountMap && statusCountMap.size() > 0) {
                count = statusCountMap.get(value);
            }
            if (null == count) {
                count = 0;
            }

            TabDto tabDto = new TabDto();
            tabDto.setName(name);
            tabDto.setType(value);
            tabDto.setCount(count);
            tabList.add(tabDto);
        }
        return tabList;
    }


    /**
     * 获取线下支付信息
     *
     * @param offlineId
     * @return
     * @throws Exception
     */
    @Override
    public OfflineDto getOffline(Integer offlineId) throws Exception {
        Assert.notNull(offlineId, "查询失败");
        OfflineBean offlineBean = offlineMapper.getById(offlineId);
        return Convert.toOfflineDto(offlineBean);
    }

    /**
     * 判断流水号是否存在
     *
     * @param serialNumber
     * @return
     * @throws Exception
     */
    @Override
    public Boolean getSerialNumberExists(String serialNumber) throws Exception {
        serialNumberCheck(serialNumber);
        return false;
    }

    /**
     * 是否存在未审核的信息
     *
     * @param ids
     * @return
     * @throws Exception
     */
    @Override
    public Boolean getUnAudit(List<Integer> ids) throws Exception {
        int unAuditCount = offlineMapper.getUnAuditCount(ids);
        if (unAuditCount > 0) {
            return true;
        }
        return false;
    }

    /**
     * 还款审核
     *
     * @param offlineAuditModifyDto
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean modifyAuditStatus(OfflineAuditModifyDto offlineAuditModifyDto) throws Exception {
        Integer offlineId = offlineAuditModifyDto.getOfflineId();
        Assert.notNull(offlineId, "审核失败");

        OfflineBean oldOfflineBean = offlineMapper.getById(offlineId);
        Assert.notNull(oldOfflineBean, "审核失败");

        Integer oldAuditStatus = oldOfflineBean.getAuditStatus();
        if (OfflineAuditStatusEnum.APPROVE.getValue() == oldAuditStatus) {
            throw new IllegalArgumentException("操作失败，此还款记录已被其它用户审核，请返回查看");
        }

        Integer auditStatus = offlineAuditModifyDto.getAuditStatus();
        String auditRemark = offlineAuditModifyDto.getAuditRemark();
        if (OfflineAuditStatusEnum.REJECT.getValue() == auditStatus && StringUtils.isBlank(auditRemark)) {
            throw new IllegalArgumentException("审核备注不能为空");
        }

        OfflineBean offlineBean = Convert.toOfflineBean(offlineAuditModifyDto);
        int result = offlineMapper.modifyAuditStatus(offlineBean);
        if (result <= 0) {
            return false;
        }
        return true;
    }

    /**
     * 获取支付数量
     *
     * @param repayType
     * @return
     */
    @Override
    public Integer getOfflineCount(Integer repayType) {
        return offlineMapper.getOfflineCount(repayType);
    }

    /**
     * 通过流水号获取线下支付信息
     *
     * @param serialNumberList
     * @return
     */
    @Override
    public Map<String, OfflineDto> getOfflineBySerialNumber(List<String> serialNumberList) {
        List<OfflineBean> offlineBeanList = offlineMapper.getOfflineBySerialNumber(serialNumberList);
        if (null == offlineBeanList || offlineBeanList.size() < 1) {
            return null;
        }
        Map<String, OfflineDto> map = new HashMap<>();
        for (OfflineBean offlineBean : offlineBeanList) {
            String serialNumber = offlineBean.getSerialNumber();
            OfflineDto offlineDto = Convert.toOfflineDto(offlineBean);
            map.put(serialNumber, offlineDto);
        }
        return map;
    }

    /**
     * 获取线下支付信息
     *
     * @param serialNumber 流水编号
     * @return
     */
    @Override
    public OfflineDto getOffline(String serialNumber, List<Integer> auditStatusList) {
        return Convert.toOfflineDto(offlineMapper.getOffline(serialNumber, auditStatusList));
    }

    /**
     * 获取用户订单线下还款tab标签数据
     *
     * @return
     * @throws Exception
     */
    @Override
    public List<TabDto> getMemberTabsStatistics() throws Exception {
        List<TabDto> result = new ArrayList<>();

        List<TabDto> tabDtoList = offlineMapper.getMemberTabsStatistics();
        for (OfflineAuditStatusEnum offlineAuditStatus : OfflineAuditStatusEnum.values()) {
            TabDto tabDto = new TabDto(offlineAuditStatus.getName(), offlineAuditStatus.getValue(), 0);
            tabDtoList.stream().forEach(tmpTab -> {
                if (offlineAuditStatus.equals(OfflineAuditStatusEnum.getEnum(tmpTab.getType()))) {
                    tabDto.setCount(tmpTab.getCount());
                }
            });
            result.add(tabDto);
        }

        return result;
    }

    /**
     * 获取线下支付数量
     *
     * @param map
     * @return
     */
    @Override
    public Integer getOfflineCount(Map<String, Object> map) {
        return offlineMapper.getOfflineCountByParams(map);
    }

}
